﻿#region Copyright information
// 
// Copyright © 2005-2013 Yongkee Cho. All rights reserved.
// 
// This code is a part of the Biological Object Library and governed under the terms of the
// GNU Lesser General  Public License (LGPL) version 2.1 which accompanies this distribution.
// For more information on the LGPL, please visit http://bol.codeplex.com/license.
// 
// - Filename: ConfusionMatrix.cs
// - Author: Yongkee Cho
// - Email: yongkeecho@gmail.com
// - Date Created: 2012-10-12 3:17 PM
// - Last Modified: 2013-01-25 3:59 PM
// 
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using BOL.Maths.Statistics;

namespace BOL.Linq
{
    public static partial class Linq
    {
        public static ClassificationMeasures ConfusionMatrix<T>(this IEnumerable<T> actual, IEnumerable<T> expected, T trueValue)
        {
            if (actual == null)
                throw new ArgumentNullException("actual");
            if (expected == null)
                throw new ArgumentNullException("expected");

            var matrix = actual.Zip(expected, (a, e) => new Tuple<bool, bool>(a.Equals(trueValue), e.Equals(trueValue))).GroupBy(x => x).
                Select(x => new { Actual = x.Key.Item1, Expected = x.Key.Item2, Count = x.Count() }).
                OrderBy(x => x.Actual).ThenBy(x => x.Expected).ToArray();

            return new ClassificationMeasures(matrix[3].Count, matrix[2].Count, matrix[1].Count, matrix[0].Count);
        }

        public static ClassificationMeasures ConfusionMatrix<TSource>(this IEnumerable<TSource> source, Func<TSource, Tuple<bool, bool>> keySelector)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (keySelector == null)
                throw new ArgumentNullException("keySelector");

            var matrix = source.GroupBy(keySelector).
                Select(x => new { Actual = x.Key.Item1, Expected = x.Key.Item2, Count = x.Count() }).
                OrderBy(x => x.Actual).ThenBy(x => x.Expected).ToArray();

            return new ClassificationMeasures(matrix[3].Count, matrix[2].Count, matrix[1].Count, matrix[0].Count);
        }
    }
}
